#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the version 3 of the GNU Lesser General Public License
#   as published by the Free Software Foundation.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU Lesser General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Copyright (c) NEC Deutschland GmbH, NEC HPC Europe
#
# $Id$
import logging
from aggmon.dp_aggregator import DPAggregator, DPAggregatorComponent
from basic_types.metric import Metric


class GroupMaxAggregator(DPAggregator):
    """
    Provides running maximum of a particular metric for the group.
    The aggregated metric will 'belong' to the group and will have
    the maximum value seen for any host of the group since the
    aggregator was started. As opposed to the GroupMaxAggregator
    this one also takes into account group metrics with its own name,
    i.e. aggregated results pushed from subgroups.
    WARNING! The handler must deal with metrics coming in from two
    subscriptions!

    This aggregator makes no sense without a hierarchy!
    
    Arguments:
       metric_name : should match a metric that is published inside the group
       agg_metric_name : name of the newly created metric
       group_path  : group hierarchy path (Example: '/siteB/rack12')
    """
    def __init__( self, metric_name, agg_metric_name, group_path, max_age=900, **kwds ):
        DPAggregator.__init__( self, metric_name, agg_metric_name, group_path, **kwds )

        # access these only when holding the lock
        self.max_age = max_age
        self.maximum_value = None
        self.last_time = None

    def handleEvent( self, metric, topic=None ):
        if self.worthy_metric( metric, topic ):
            value = metric.value
        else:
            return
        if not isinstance( value, ( int, long, float ) ):
            return
        params = {}
        self._lock.acquire()
        try:
            if (self.maximum_value is not None and value > self.maximum_value) \
                or self.maximum_value is None \
                or (metric.time - self.last_time > self.max_age):
                self.maximum_value = value
                self.last_time = metric.time
                params = { "name": self.agg_metric_name,
                           "value": self.maximum_value,
                           "source": "aggregator",
                           "time":  metric.time,
                           "host": self._group_topic }
        finally:
            self._lock.release()
        if len( params ) > 0:
            max_metric = Metric( **params )
            self.publish( max_metric )


class GroupMaxAggregatorComponent(DPAggregatorComponent):
    def __init__( self, *args, **kwds ):
        DPAggregatorComponent.__init__( self, *args, **kwds)
        self.allowed_kwds.extend( ["max_age"] )

    def instantiate( self, *args, **kwds ):
        self.instance = None
        try:
            logging.debug( "instantiating: %s" % self.name )
            self.instance = GroupMaxAggregator( *args, **kwds )
        except Exception, e:
            raise e
